Initialization and import of data
install.packages("VGAM")
essai de l'URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/VGAM_1.1-5.tgz'
Content type 'application/x-gzip' length 7281930 bytes (6.9 MB)
==================================================
downloaded 6.9 MB
The downloaded binary packages are in
/var/folders/6g/jj4zrn8n0pv9nvlgqdvg6k500000gn/T//RtmpT1znVe/downloaded_packages
names(dataSet)
[1] "battery_power" "blue" "clock_speed" "dual_sim" "fc" "four_g" "int_memory" "m_dep" "mobile_wt" "n_cores" "pc" "px_height" "px_width" "ram"
[15] "sc_h" "sc_w" "talk_time" "three_g" "touch_screen" "wifi" "price_range"
Display of the set of data.
Columns : battery_power, blue, clock_speed, dual_sim, fc, four_g,int_memory, m_dep, mobile_wt, n_cores, pc, px_height, px_width, ram, sc_h, sc_w, talk_time, three_g, touch_screen, wifi, price_range
battery_power:Total energy a battery can store in one time measured in mAh blue:Has bluetooth or not clock_speed:speed at which microprocessor executes instructions dual_sim:Has dual sim support or not fc:Front Camera mega pixels four_g:Has 4G or not int_memory:Internal Memory in Gigabytes m_dep:Mobile Depth in cm mobile_wt:Weight of mobile phone n_cores:Number of cores of processor pc:Primary Camera mega pixels px_height:Pixel Resolution Height px_width:Pixel Resolution Width ram:Random Access Memory in Megabytes sc_h:Screen Height of mobile in cm sc_w:Screen Width of mobile in cm talk_time:longest time that a single battery charge will last when you are three_g:Has 3G or not touch_screen:Has touch screen or not wifi:Has wifi or not price_range: This is the target variable with value of 0(low cost), 1(medium cost), 2(high cost) and 3(very high cost).
dim(dataSet)
[1] 2000 21
class(dataSet)
[1] "data.frame"
head(dataSet)
sapply(dataSet, class)
battery_power blue clock_speed dual_sim fc four_g int_memory m_dep mobile_wt n_cores pc px_height px_width ram sc_h sc_w talk_time
"integer" "integer" "numeric" "integer" "integer" "integer" "integer" "numeric" "integer" "integer" "integer" "integer" "integer" "integer" "integer" "integer" "integer"
three_g touch_screen wifi price_range
"integer" "integer" "integer" "integer"
summary(dataSet)
battery_power blue clock_speed dual_sim fc four_g int_memory m_dep mobile_wt n_cores pc px_height px_width ram
Min. : 501.0 Min. :0.000 Min. :0.500 Min. :0.0000 Min. : 0.000 Min. :0.0000 Min. : 2.00 Min. :0.1000 Min. : 80.0 Min. :1.000 Min. : 0.000 Min. : 0.0 Min. : 500.0 Min. : 256
1st Qu.: 851.8 1st Qu.:0.000 1st Qu.:0.700 1st Qu.:0.0000 1st Qu.: 1.000 1st Qu.:0.0000 1st Qu.:16.00 1st Qu.:0.2000 1st Qu.:109.0 1st Qu.:3.000 1st Qu.: 5.000 1st Qu.: 282.8 1st Qu.: 874.8 1st Qu.:1208
Median :1226.0 Median :0.000 Median :1.500 Median :1.0000 Median : 3.000 Median :1.0000 Median :32.00 Median :0.5000 Median :141.0 Median :4.000 Median :10.000 Median : 564.0 Median :1247.0 Median :2146
Mean :1238.5 Mean :0.495 Mean :1.522 Mean :0.5095 Mean : 4.309 Mean :0.5215 Mean :32.05 Mean :0.5018 Mean :140.2 Mean :4.521 Mean : 9.916 Mean : 645.1 Mean :1251.5 Mean :2124
3rd Qu.:1615.2 3rd Qu.:1.000 3rd Qu.:2.200 3rd Qu.:1.0000 3rd Qu.: 7.000 3rd Qu.:1.0000 3rd Qu.:48.00 3rd Qu.:0.8000 3rd Qu.:170.0 3rd Qu.:7.000 3rd Qu.:15.000 3rd Qu.: 947.2 3rd Qu.:1633.0 3rd Qu.:3064
Max. :1998.0 Max. :1.000 Max. :3.000 Max. :1.0000 Max. :19.000 Max. :1.0000 Max. :64.00 Max. :1.0000 Max. :200.0 Max. :8.000 Max. :20.000 Max. :1960.0 Max. :1998.0 Max. :3998
sc_h sc_w talk_time three_g touch_screen wifi price_range
Min. : 5.00 Min. : 0.000 Min. : 2.00 Min. :0.0000 Min. :0.000 Min. :0.000 Min. :0.00
1st Qu.: 9.00 1st Qu.: 2.000 1st Qu.: 6.00 1st Qu.:1.0000 1st Qu.:0.000 1st Qu.:0.000 1st Qu.:0.75
Median :12.00 Median : 5.000 Median :11.00 Median :1.0000 Median :1.000 Median :1.000 Median :1.50
Mean :12.31 Mean : 5.767 Mean :11.01 Mean :0.7615 Mean :0.503 Mean :0.507 Mean :1.50
3rd Qu.:16.00 3rd Qu.: 9.000 3rd Qu.:16.00 3rd Qu.:1.0000 3rd Qu.:1.000 3rd Qu.:1.000 3rd Qu.:2.25
Max. :19.00 Max. :18.000 Max. :20.00 Max. :1.0000 Max. :1.000 Max. :1.000 Max. :3.00
library(ggplot2)
df <- data.frame(
group = c(0, 1, 2, 3),
value = c(sum(dataSet$price_range==0), sum(dataSet$price_range==1), sum(dataSet$price_range==2), sum(dataSet$price_range==3))
)
bp<- ggplot(df, aes(x="", y=value, fill=group))+
geom_bar(width = 1, stat = "identity")
bp

pie <- bp + coord_polar("y", start=0)
pie

fig(18, 16)
Correlation plot showing the features that are the most linked between each others
library(ggcorrplot)
corr <- round(cor(dataSet), 8)
ggcorrplot(corr)

fig(18, 16)
str(dataSet)
'data.frame': 2000 obs. of 21 variables:
$ battery_power: int 842 1021 563 615 1821 1859 1821 1954 1445 509 ...
$ blue : int 0 1 1 1 1 0 0 0 1 1 ...
$ clock_speed : num 2.2 0.5 0.5 2.5 1.2 0.5 1.7 0.5 0.5 0.6 ...
$ dual_sim : int 0 1 1 0 0 1 0 1 0 1 ...
$ fc : int 1 0 2 0 13 3 4 0 0 2 ...
$ four_g : int 0 1 1 0 1 0 1 0 0 1 ...
$ int_memory : int 7 53 41 10 44 22 10 24 53 9 ...
$ m_dep : num 0.6 0.7 0.9 0.8 0.6 0.7 0.8 0.8 0.7 0.1 ...
$ mobile_wt : int 188 136 145 131 141 164 139 187 174 93 ...
$ n_cores : int 2 3 5 6 2 1 8 4 7 5 ...
$ pc : int 2 6 6 9 14 7 10 0 14 15 ...
$ px_height : int 20 905 1263 1216 1208 1004 381 512 386 1137 ...
$ px_width : int 756 1988 1716 1786 1212 1654 1018 1149 836 1224 ...
$ ram : int 2549 2631 2603 2769 1411 1067 3220 700 1099 513 ...
$ sc_h : int 9 17 11 16 8 17 13 16 17 19 ...
$ sc_w : int 7 3 2 8 2 1 8 3 1 10 ...
$ talk_time : int 19 7 9 11 15 10 18 5 20 12 ...
$ three_g : int 0 1 1 1 1 1 1 1 1 1 ...
$ touch_screen : int 0 1 1 0 1 0 0 1 0 0 ...
$ wifi : int 1 0 0 0 0 0 1 1 0 0 ...
$ price_range : int 1 2 2 2 1 1 3 0 0 0 ...
Displaying the cell percentages of different features of the dataSet
prop.table(table(dataSet$blue)) # cell percentages
0 1
0.505 0.495
prop.table(table(dataSet$dual_sim)) # cell percentages
0 1
0.4905 0.5095
prop.table(table(dataSet$four_g)) # cell percentages
0 1
0.4785 0.5215
prop.table(table(dataSet$three_g)) # cell percentages
0 1
0.2385 0.7615
prop.table(table(dataSet$touch_screen)) # cell percentages
0 1
0.497 0.503
prop.table(table(dataSet$wifi)) # cell percentages
0 1
0.493 0.507
Comparing the impact of two features on the mobile’s price range
library(ggplot2)
data = data.frame(Dimensions_in_cm = c(dataSet$sc_h, dataSet$sc_w),
Screen = rep(c("Height", "Width"), c(length(dataSet$sc_h), length(dataSet$sc_w))))
ggplot(data, aes(Dimensions_in_cm, fill = Screen)) +
geom_bar(position = 'identity', alpha = .6)

Comparing the impact of two features on the mobile’s price range
library(ggplot2)
library(gridExtra)
dataSet$price_range <- as.factor(dataSet$price_range)
p1 <- ggplot(dataSet, aes(x=px_width, y = px_height, color=price_range)) +
geom_boxplot(outlier.colour="red", outlier.shape=8,
outlier.size=4) +
labs(title = "Pixel Resolution Height vs Pixel Resolution Width")
p2 <- ggplot(dataSet, aes(x=price_range, y = ram, color=price_range)) +
geom_boxplot(outlier.colour="red", outlier.shape=8,
outlier.size=4) +
labs(title = "RAM vs Price Range")
grid.arrange(p1, p2,nrow = 1)

fig(24, 20)
Interquartile range of two features at a time
library(ggplot2)
library(gridExtra)
dataSet$price_range <- as.factor(dataSet$price_range)
p3 <- ggplot(dataSet, aes(x=price_range, y = int_memory, color=price_range)) +
geom_boxplot(outlier.colour="red", outlier.shape=8,
outlier.size=4) +
labs(title = "int_memory vs Price Range")
p4 <- ggplot(dataSet, aes(x=price_range, y = battery_power, color=price_range)) +
geom_boxplot(outlier.colour="red", outlier.shape=8,
outlier.size=4) +
labs(title = "Battery power vs Price Range")
grid.arrange(p3, p4,nrow = 1)

fig(24, 20)
Data classification depending on battery power, ram, memory, clock speed and number of cores
library(dplyr)
library(ggplot2)
library(gridExtra)
#Battery_power IQR
firstQuantile <- quantile(dataSet$battery_power, 0.25)
thirdQuantile <- quantile(dataSet$battery_power, 0.75)
battery_powerIQR <- dataSet %>% filter(dataSet$battery_power > firstQuantile & dataSet$battery_power < thirdQuantile)
#Int Memory IQR
firstQuantile <- quantile(dataSet$int_memory , 0.25)
thirdQuantile <- quantile(dataSet$int_memory, 0.75)
int_memoryIQR <- dataSet %>% filter(dataSet$int_memory > firstQuantile & dataSet$int_memory < thirdQuantile)
#ram IQR
firstQuantile <- quantile(dataSet$ram , 0.25)
thirdQuantile <- quantile(dataSet$ram, 0.75)
ramIQR <- dataSet %>% filter(dataSet$ram > firstQuantile & dataSet$ram < thirdQuantile)
p2 <- ggplot(ramIQR, aes(x=price_range, y = ram, color=price_range)) +
geom_boxplot(outlier.colour="red", outlier.shape=8,
outlier.size=4) +
labs(title = "IQR RAM vs Price Range")
p3 <- ggplot(int_memoryIQR, aes(x=price_range, y = int_memory, color=price_range)) +
geom_boxplot(outlier.colour="red", outlier.shape=8,
outlier.size=4) +
labs(title = "IQR int memory vs Price Range")
p4 <- ggplot(battery_powerIQR, aes(x=price_range, y = battery_power, color=price_range)) +
geom_boxplot(outlier.colour="red", outlier.shape=8,
outlier.size=4) +
labs(title = "IQR battery power vs Price Range")
grid.arrange(p2, p3, p4,nrow = 1)

fig(24, 20)
3D graphic
install.packages("pacman")
essai de l'URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/pacman_0.5.1.tgz'
Content type 'application/x-gzip' length 379950 bytes (371 KB)
==================================================
downloaded 371 KB
The downloaded binary packages are in
/var/folders/6g/jj4zrn8n0pv9nvlgqdvg6k500000gn/T//RtmpT1znVe/downloaded_packages
library(ggplot2)
install.packages("dplyr")
essai de l'URL 'https://cran.rstudio.com/bin/macosx/contrib/4.0/dplyr_1.0.5.tgz'
Content type 'application/x-gzip' length 1251016 bytes (1.2 MB)
==================================================
downloaded 1.2 MB
The downloaded binary packages are in
/var/folders/6g/jj4zrn8n0pv9nvlgqdvg6k500000gn/T//RtmpT1znVe/downloaded_packages
p <- ggplot(dataSet, aes(battery_power, ram, color = price_range))+
geom_point()
p + stat_ellipse()

p <- ggplot(dataSet, aes(int_memory, ram, color = price_range))+
geom_point()
p + stat_ellipse()

Kmeans classifier on battery and ram for price range
library(tidyverse)
library(plotly)
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
Attachement du package : ‘plotly’
The following object is masked from ‘package:rio’:
export
The following object is masked from ‘package:ggplot2’:
last_plot
The following object is masked from ‘package:stats’:
filter
The following object is masked from ‘package:graphics’:
layout
# Creating the graphic
p <- plot_ly(
dataSet, x = dataSet$battery_power, y = dataSet$ram, z = dataSet$int_memory,
color = dataSet$price_range) %>%
add_markers(size=1) %>%
layout(
scene = list(xaxis = list(title = 'Battery Power'),
yaxis = list(title = 'Ram'),
zaxis = list(title = 'Memoire interne'))
)
p
Logistic Regression classifier on battery and ram for price range

kNN classifier on battery and ram for price range

SVM classifier on battery and ram for price range
print(paste0(k, paste0(" nbFold, Score F : ", score)))
[1] "10 nbFold, Score F : 0.937552039966694"
Global naiveBayes test on qualifer
library(e1071)
library(MLmetrics)
percentage_of_data_for_training <- 0.90
extractDataFromDataSet <- dataSet %>%select(1,7,14,21)
nbColumnForTraining <- nrow(extractDataFromDataSet)*percentage_of_data_for_training
nbRowForTraining <- ncol(extractDataFromDataSet)
m <- naiveBayes(
extractDataFromDataSet[0:nbColumnForTraining,-nbRowForTraining],
extractDataFromDataSet[0:nbColumnForTraining,nbRowForTraining],
eps = 1)
pred_result <- predict(m, extractDataFromDataSet[nbColumnForTraining:nrow(extractDataFromDataSet),])
true_result <- extractDataFromDataSet[nbColumnForTraining:nrow(extractDataFromDataSet),ncol(extractDataFromDataSet)]
score <- F1_Score(y_pred = pred_result, y_true = true_result)
print(score)
LS0tCnRpdGxlOiAiQW5hbHl6aW5nIERhdGEgU2V0IE1vYmlsZSBQcmljZSBXaXRoIEttZWFucyBhbmQgTG9naXN0aWMgUmVncmVzc2lvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKSW5pdGlhbGl6YXRpb24gYW5kIGltcG9ydCBvZiBkYXRhCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikKaW5zdGFsbC5wYWNrYWdlcygicGFjbWFuIikKaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKQppbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQppbnN0YWxsLnBhY2thZ2VzKCJWR0FNIikKaW5zdGFsbC5wYWNrYWdlcygnTUxtZXRyaWNzJykKCmxpYnJhcnkodGlkeXZlcnNlKQoKZmlnIDwtIGZ1bmN0aW9uKHdpZHRoLCBoZWlndGgpewogICAgIG9wdGlvbnMocmVwci5wbG90LndpZHRoID0gd2lkdGgsIHJlcHIucGxvdC5oZWlnaHQgPSBoZWlndGgpCn0KCmxpYnJhcnkocGFjbWFuKQoKcGFjbWFuOjpwX2xvYWQocGFjbWFuLGRwbHlyLCBnZ3Bsb3QyLCByaW8sIGdyaWRFeHRyYSwgc2NhbGVzLCBnZ2NvcnJwbG90LCBjYXJldCwgZTEwNzEpCgpkYXRhU2V0IDwtIHJlYWQuY3N2KCdkYXRhL3RyYWluLmNzdicpCmBgYAoKCmBgYHtyfQpuYW1lcyhkYXRhU2V0KQpgYGAKCkRpc3BsYXkgb2YgdGhlIHNldCBvZiBkYXRhLgoKQ29sdW1ucyA6IGJhdHRlcnlfcG93ZXIsIGJsdWUsIGNsb2NrX3NwZWVkLCBkdWFsX3NpbSwgZmMsIGZvdXJfZyxpbnRfbWVtb3J5LCBtX2RlcCwgbW9iaWxlX3d0LCBuX2NvcmVzLCBwYywgcHhfaGVpZ2h0LCBweF93aWR0aCwgcmFtLCBzY19oLCBzY193LCB0YWxrX3RpbWUsIHRocmVlX2csIHRvdWNoX3NjcmVlbiwgd2lmaSwgcHJpY2VfcmFuZ2UKCmJhdHRlcnlfcG93ZXI6VG90YWwgZW5lcmd5IGEgYmF0dGVyeSBjYW4gc3RvcmUgaW4gb25lIHRpbWUgbWVhc3VyZWQgaW4gbUFoCmJsdWU6SGFzIGJsdWV0b290aCBvciBub3QKY2xvY2tfc3BlZWQ6c3BlZWQgYXQgd2hpY2ggbWljcm9wcm9jZXNzb3IgZXhlY3V0ZXMgaW5zdHJ1Y3Rpb25zCmR1YWxfc2ltOkhhcyBkdWFsIHNpbSBzdXBwb3J0IG9yIG5vdApmYzpGcm9udCBDYW1lcmEgbWVnYSBwaXhlbHMKZm91cl9nOkhhcyA0RyBvciBub3QKaW50X21lbW9yeTpJbnRlcm5hbCBNZW1vcnkgaW4gR2lnYWJ5dGVzCm1fZGVwOk1vYmlsZSBEZXB0aCBpbiBjbQptb2JpbGVfd3Q6V2VpZ2h0IG9mIG1vYmlsZSBwaG9uZQpuX2NvcmVzOk51bWJlciBvZiBjb3JlcyBvZiBwcm9jZXNzb3IKcGM6UHJpbWFyeSBDYW1lcmEgbWVnYSBwaXhlbHMKcHhfaGVpZ2h0OlBpeGVsIFJlc29sdXRpb24gSGVpZ2h0CnB4X3dpZHRoOlBpeGVsIFJlc29sdXRpb24gV2lkdGgKcmFtOlJhbmRvbSBBY2Nlc3MgTWVtb3J5IGluIE1lZ2FieXRlcwpzY19oOlNjcmVlbiBIZWlnaHQgb2YgbW9iaWxlIGluIGNtCnNjX3c6U2NyZWVuIFdpZHRoIG9mIG1vYmlsZSBpbiBjbQp0YWxrX3RpbWU6bG9uZ2VzdCB0aW1lIHRoYXQgYSBzaW5nbGUgYmF0dGVyeSBjaGFyZ2Ugd2lsbCBsYXN0IHdoZW4geW91IGFyZQp0aHJlZV9nOkhhcyAzRyBvciBub3QKdG91Y2hfc2NyZWVuOkhhcyB0b3VjaCBzY3JlZW4gb3Igbm90CndpZmk6SGFzIHdpZmkgb3Igbm90CnByaWNlX3JhbmdlOiBUaGlzIGlzIHRoZSB0YXJnZXQgdmFyaWFibGUgd2l0aCB2YWx1ZSBvZiAwKGxvdyBjb3N0KSwgMShtZWRpdW0gY29zdCksIDIoaGlnaCBjb3N0KSBhbmQgMyh2ZXJ5IGhpZ2ggY29zdCkuCgpgYGB7cn0KZGltKGRhdGFTZXQpCmNsYXNzKGRhdGFTZXQpCmhlYWQoZGF0YVNldCkKc2FwcGx5KGRhdGFTZXQsIGNsYXNzKQpgYGAKCgpgYGB7cn0Kc3VtbWFyeShkYXRhU2V0KQpgYGAKCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCmRmIDwtIGRhdGEuZnJhbWUoCiAgZ3JvdXAgPSBjKDAsIDEsIDIsIDMpLAogIHZhbHVlID0gYyhzdW0oZGF0YVNldCRwcmljZV9yYW5nZT09MCksIHN1bShkYXRhU2V0JHByaWNlX3JhbmdlPT0xKSwgc3VtKGRhdGFTZXQkcHJpY2VfcmFuZ2U9PTIpLCBzdW0oZGF0YVNldCRwcmljZV9yYW5nZT09MykpCiAgKQpwaWUgPC0gYnAgKyBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApCnBpZQpmaWcoMTgsIDE2KQpgYGAKCkNvcnJlbGF0aW9uIHBsb3Qgc2hvd2luZyB0aGUgZmVhdHVyZXMgdGhhdCBhcmUgdGhlIG1vc3QgbGlua2VkIGJldHdlZW4gZWFjaCBvdGhlcnMKYGBge3J9CmxpYnJhcnkoZ2djb3JycGxvdCkKY29yciA8LSByb3VuZChjb3IoZGF0YVNldCksIDgpCmdnY29ycnBsb3QoY29ycikKZmlnKDE4LCAxNikKYGBgCgoKYGBge3J9CnN0cihkYXRhU2V0KQpgYGAKCkRpc3BsYXlpbmcgdGhlIGNlbGwgcGVyY2VudGFnZXMgb2YgZGlmZmVyZW50IGZlYXR1cmVzIG9mIHRoZSBkYXRhU2V0CmBgYHtyfQpwcm9wLnRhYmxlKHRhYmxlKGRhdGFTZXQkYmx1ZSkpICMgY2VsbCBwZXJjZW50YWdlcwpwcm9wLnRhYmxlKHRhYmxlKGRhdGFTZXQkZHVhbF9zaW0pKSAjIGNlbGwgcGVyY2VudGFnZXMKcHJvcC50YWJsZSh0YWJsZShkYXRhU2V0JGZvdXJfZykpICMgY2VsbCBwZXJjZW50YWdlcwpwcm9wLnRhYmxlKHRhYmxlKGRhdGFTZXQkdGhyZWVfZykpICMgY2VsbCBwZXJjZW50YWdlcwpwcm9wLnRhYmxlKHRhYmxlKGRhdGFTZXQkdG91Y2hfc2NyZWVuKSkgIyBjZWxsIHBlcmNlbnRhZ2VzCnByb3AudGFibGUodGFibGUoZGF0YVNldCR3aWZpKSkgIyBjZWxsIHBlcmNlbnRhZ2VzCmBgYAoKQ29tcGFyaW5nIHRoZSBpbXBhY3Qgb2YgdHdvIGZlYXR1cmVzIG9uIHRoZSBtb2JpbGUncyBwcmljZSByYW5nZQpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKZGF0YVNldCRwcmljZV9yYW5nZSA8LSBhcy5mYWN0b3IoZGF0YVNldCRwcmljZV9yYW5nZSkKcDEgPC0gIGdncGxvdChkYXRhU2V0LCBhZXMoeD1weF93aWR0aCwgeSA9IHB4X2hlaWdodCwgY29sb3I9cHJpY2VfcmFuZ2UpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJyZWQiLCBvdXRsaWVyLnNoYXBlPTgsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZT00KSArCiAgbGFicyh0aXRsZSA9ICJQaXhlbCBSZXNvbHV0aW9uIEhlaWdodCB2cyBQaXhlbCBSZXNvbHV0aW9uIFdpZHRoIikKcDIgPC0gZ2dwbG90KGRhdGFTZXQsIGFlcyh4PXByaWNlX3JhbmdlLCB5ID0gcmFtLCBjb2xvcj1wcmljZV9yYW5nZSkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9InJlZCIsIG91dGxpZXIuc2hhcGU9OCwKICAgICAgICAgICAgICAgb3V0bGllci5zaXplPTQpICsKICBsYWJzKHRpdGxlID0gIlJBTSB2cyBQcmljZSBSYW5nZSIpCmdyaWQuYXJyYW5nZShwMSwgcDIsbnJvdyA9IDEpCmZpZygyNCwgMjApCmBgYAoKQ29tcGFyaW5nIHRoZSBpbXBhY3Qgb2YgdHdvIGZlYXR1cmVzIG9uIHRoZSBtb2JpbGUncyBwcmljZSByYW5nZQpgYGB7cn0KbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGdyaWRFeHRyYSkKZGF0YVNldCRwcmljZV9yYW5nZSA8LSBhcy5mYWN0b3IoZGF0YVNldCRwcmljZV9yYW5nZSkKcDMgPC0gZ2dwbG90KGRhdGFTZXQsIGFlcyh4PXByaWNlX3JhbmdlLCB5ID0gaW50X21lbW9yeSwgY29sb3I9cHJpY2VfcmFuZ2UpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJyZWQiLCBvdXRsaWVyLnNoYXBlPTgsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZT00KSArCiAgbGFicyh0aXRsZSA9ICJpbnRfbWVtb3J5IHZzIFByaWNlIFJhbmdlIikKcDQgPC0gZ2dwbG90KGRhdGFTZXQsIGFlcyh4PXByaWNlX3JhbmdlLCB5ID0gYmF0dGVyeV9wb3dlciwgY29sb3I9cHJpY2VfcmFuZ2UpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJyZWQiLCBvdXRsaWVyLnNoYXBlPTgsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZT00KSArCiAgbGFicyh0aXRsZSA9ICJCYXR0ZXJ5IHBvd2VyIHZzIFByaWNlIFJhbmdlIikKZ3JpZC5hcnJhbmdlKHAzLCBwNCxucm93ID0gMSkKZmlnKDI0LCAyMCkKYGBgCgpJbnRlcnF1YXJ0aWxlIHJhbmdlIG9mIHR3byBmZWF0dXJlcyBhdCBhIHRpbWUKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShncmlkRXh0cmEpCiNCYXR0ZXJ5X3Bvd2VyIElRUgpmaXJzdFF1YW50aWxlIDwtIHF1YW50aWxlKGRhdGFTZXQkYmF0dGVyeV9wb3dlciwgMC4yNSkKdGhpcmRRdWFudGlsZSA8LSBxdWFudGlsZShkYXRhU2V0JGJhdHRlcnlfcG93ZXIsIDAuNzUpCmJhdHRlcnlfcG93ZXJJUVIgPC0gZGF0YVNldCAlPiUgZmlsdGVyKGRhdGFTZXQkYmF0dGVyeV9wb3dlciA+IGZpcnN0UXVhbnRpbGUgJiBkYXRhU2V0JGJhdHRlcnlfcG93ZXIgPCB0aGlyZFF1YW50aWxlKQojSW50IE1lbW9yeSBJUVIKZmlyc3RRdWFudGlsZSA8LSBxdWFudGlsZShkYXRhU2V0JGludF9tZW1vcnkgLCAwLjI1KQp0aGlyZFF1YW50aWxlIDwtIHF1YW50aWxlKGRhdGFTZXQkaW50X21lbW9yeSwgMC43NSkKaW50X21lbW9yeUlRUiA8LSBkYXRhU2V0ICU+JSBmaWx0ZXIoZGF0YVNldCRpbnRfbWVtb3J5ID4gZmlyc3RRdWFudGlsZSAmIGRhdGFTZXQkaW50X21lbW9yeSA8IHRoaXJkUXVhbnRpbGUpCiNyYW0gSVFSCmZpcnN0UXVhbnRpbGUgPC0gcXVhbnRpbGUoZGF0YVNldCRyYW0gLCAwLjI1KQp0aGlyZFF1YW50aWxlIDwtIHF1YW50aWxlKGRhdGFTZXQkcmFtLCAwLjc1KQpyYW1JUVIgPC0gZGF0YVNldCAlPiUgZmlsdGVyKGRhdGFTZXQkcmFtID4gZmlyc3RRdWFudGlsZSAmIGRhdGFTZXQkcmFtIDwgdGhpcmRRdWFudGlsZSkKCnAyIDwtIGdncGxvdChyYW1JUVIsIGFlcyh4PXByaWNlX3JhbmdlLCB5ID0gcmFtLCBjb2xvcj1wcmljZV9yYW5nZSkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9InJlZCIsIG91dGxpZXIuc2hhcGU9OCwKICAgICAgICAgICAgICAgb3V0bGllci5zaXplPTQpICsKICBsYWJzKHRpdGxlID0gIklRUiBSQU0gdnMgUHJpY2UgUmFuZ2UiKQoKcDMgPC0gZ2dwbG90KGludF9tZW1vcnlJUVIsIGFlcyh4PXByaWNlX3JhbmdlLCB5ID0gaW50X21lbW9yeSwgY29sb3I9cHJpY2VfcmFuZ2UpKSArCiAgZ2VvbV9ib3hwbG90KG91dGxpZXIuY29sb3VyPSJyZWQiLCBvdXRsaWVyLnNoYXBlPTgsCiAgICAgICAgICAgICAgIG91dGxpZXIuc2l6ZT00KSArCiAgbGFicyh0aXRsZSA9ICJJUVIgaW50IG1lbW9yeSB2cyBQcmljZSBSYW5nZSIpCgpwNCA8LSBnZ3Bsb3QoYmF0dGVyeV9wb3dlcklRUiwgYWVzKHg9cHJpY2VfcmFuZ2UsIHkgPSBiYXR0ZXJ5X3Bvd2VyLCBjb2xvcj1wcmljZV9yYW5nZSkpICsKICBnZW9tX2JveHBsb3Qob3V0bGllci5jb2xvdXI9InJlZCIsIG91dGxpZXIuc2hhcGU9OCwKICAgICAgICAgICAgICAgb3V0bGllci5zaXplPTQpICsKICBsYWJzKHRpdGxlID0gIklRUiBiYXR0ZXJ5IHBvd2VyIHZzIFByaWNlIFJhbmdlIikKZ3JpZC5hcnJhbmdlKHAyLCBwMywgcDQsbnJvdyA9IDEpCmZpZygyNCwgMjApCmBgYAoKRGF0YSBjbGFzc2lmaWNhdGlvbiBkZXBlbmRpbmcgb24gYmF0dGVyeSBwb3dlciwgcmFtLCBtZW1vcnksIGNsb2NrIHNwZWVkIGFuZCBudW1iZXIgb2YgY29yZXMKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKcCA8LSBnZ3Bsb3QoZGF0YVNldCwgYWVzKGJhdHRlcnlfcG93ZXIsIHJhbSwgY29sb3IgPSBwcmljZV9yYW5nZSkpKwogIGdlb21fcG9pbnQoKQpwICsgc3RhdF9lbGxpcHNlKCkKcCA8LSBnZ3Bsb3QoZGF0YVNldCwgYWVzKGludF9tZW1vcnksIHJhbSwgY29sb3IgPSBwcmljZV9yYW5nZSkpKwogIGdlb21fcG9pbnQoKQpwICsgc3RhdF9lbGxpcHNlKCkKYGBgCgoKM0QgZ3JhcGhpYyAKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHBsb3RseSkKCiMgQ3JlYXRpbmcgdGhlIGdyYXBoaWMKcCA8LSBwbG90X2x5KAogIGRhdGFTZXQsIHggPSBkYXRhU2V0JGJhdHRlcnlfcG93ZXIsIHkgPSBkYXRhU2V0JHJhbSwgeiA9IGRhdGFTZXQkaW50X21lbW9yeSwgCiAgY29sb3IgPSBkYXRhU2V0JHByaWNlX3JhbmdlKSAlPiUKICBhZGRfbWFya2VycyhzaXplPTEpICU+JQogIGxheW91dCgKICAgIHNjZW5lID0gbGlzdCh4YXhpcyA9IGxpc3QodGl0bGUgPSAnQmF0dGVyeSBQb3dlcicpLAogICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICdSYW0nKSwKICAgICAgICB6YXhpcyA9IGxpc3QodGl0bGUgPSAnTWVtb2lyZSBpbnRlcm5lJykpCiAgICAgICAgKQpwCmBgYAoKS21lYW5zIGNsYXNzaWZpZXIgb24gYmF0dGVyeSBhbmQgcmFtIGZvciBwcmljZSByYW5nZQpgYGB7cn0KbGlicmFyeShNTG1ldHJpY3MpCgpleHRyYWN0RGF0YUZyb21EYXRhU2V0IDwtICBkYXRhU2V0ICU+JXNlbGVjdCgxLCAxNCwgMjEpICMgYmF0dGVyeSA9IDEgLG1lbW9yeSA9IDcsIHJhbSA9IDE0LCBtb2JpbGUgY2xhc3MgPSAyMQpleHRyYWN0RGF0YUZyb21EYXRhU2V0JHByaWNlX3JhbmdlCnRlbXBvIDwtIGFzLm51bWVyaWMoZXh0cmFjdERhdGFGcm9tRGF0YVNldCRwcmljZV9yYW5nZSkKdGVtcG8KZXh0cmFjdERhdGFGcm9tRGF0YVNldCRwcmljZV9yYW5nZSA8LSB0ZW1wbwpleHRyYWN0RGF0YUZyb21EYXRhU2V0JHByaWNlX3JhbmdlCnNldC5zZWVkKDEwMSkKZXh0cmFjdERhdGFGcm9tRGF0YVNldFssMToyXQpnZ3Bsb3QoZXh0cmFjdERhdGFGcm9tRGF0YVNldCxhZXMoeCA9IGV4dHJhY3REYXRhRnJvbURhdGFTZXQkYmF0dGVyeV9wb3dlciwgeSA9IGV4dHJhY3REYXRhRnJvbURhdGFTZXQkcmFtLCBjb2w9IGV4dHJhY3REYXRhRnJvbURhdGFTZXQkcHJpY2VfcmFuZ2UpKSArIGdlb21fcG9pbnQoKQpkYXRhQ2x1c3RlciA8LSBrbWVhbnMoZXh0cmFjdERhdGFGcm9tRGF0YVNldFssMToyXSwgY2VudGVyPTQsIG5zdGFydD0xMDApCmRhdGFDbHVzdGVyCmRhdGFDbHVzdGVyJGNsdXN0ZXIKZGF0YUNsdXN0ZXIkY2x1c3RlciA8LSBkYXRhQ2x1c3RlciRjbHVzdGVyIC0gMQpleHRyYWN0RGF0YUZyb21EYXRhU2V0JHByaWNlX3JhbmdlIDwtIGV4dHJhY3REYXRhRnJvbURhdGFTZXQkcHJpY2VfcmFuZ2UtMQpkYXRhQ2x1c3RlciRjbHVzdGVyCnRhYmxlKGRhdGFDbHVzdGVyJGNsdXN0ZXIsIGV4dHJhY3REYXRhRnJvbURhdGFTZXQkcHJpY2VfcmFuZ2UpCmxpYnJhcnkoY2x1c3RlcikKY2x1c3Bsb3QoZXh0cmFjdERhdGFGcm9tRGF0YVNldCwgZGF0YUNsdXN0ZXIkY2x1c3RlciwgY29sb3I9VCwgc2hhZGU9VCwgbGFiZWxzPTAsIGxpbmVzPTApCgpzY29yZSA8LSBGMV9TY29yZSh5X3ByZWQgPSBkYXRhQ2x1c3RlciRjbHVzdGVyLCB5X3RydWUgPSBleHRyYWN0RGF0YUZyb21EYXRhU2V0JHByaWNlX3JhbmdlKQpwcmludChwYXN0ZTAoIlNjb3JlIEYgOiAiLCBzY29yZSkpCmBgYAoKTG9naXN0aWMgUmVncmVzc2lvbiBjbGFzc2lmaWVyIG9uIGJhdHRlcnkgYW5kIHJhbSBmb3IgcHJpY2UgcmFuZ2UKYGBge3J9CmxpYnJhcnkoVkdBTSkKc2VlZCA8LSAxODA5CnNldC5zZWVkKHNlZWQpCgpsaWJyYXJ5KGNhcmV0KSAjIEZvciB0aGUgY29uZnVzaW9uIG1hdHJpeApsaWJyYXJ5KE1MbWV0cmljcykKCm4gPC0gbnJvdyhkYXRhU2V0KQojIFNlbGVjdCBvbmx5IHRoZSByZWxldmFudCB2YXJpYWJsZXMKUmVkdWNlZERhdGFTZXQgPC0gc3Vic2V0KGRhdGFTZXQsIHNlbGVjdD1jKCJiYXR0ZXJ5X3Bvd2VyIiwgInJhbSIsICJwcmljZV9yYW5nZSIpKQoKIyBEZWZpbmUgdGhlIGZvbGRzCm5fZm9sZHMgPC0gMTAgIyBudW1iZXIgb2YgZm9sZHMKZm9sZHNfaSA8LSBzYW1wbGUocmVwKDE6bl9mb2xkcywgbGVuZ3RoLm91dCA9IG4pKSAjIGdlbmVyYXRlIHRoZSBmb2xkcwoKIyBJbml0aWFsaXphdGlvbiBvZiB0aGUgb3V0cHV0cwphY2N1cmFjeSA8LSBtYXRyaXgoTkEsIG5yb3cgPSBuX2ZvbGRzLCBuY29sID0gMSkKc2Vuc2l0aXZpdHkgPC0gbWF0cml4KE5BLCBucm93ID0gbl9mb2xkcywgbmNvbCA9IDEpCnNwZWNpZmljaXR5IDwtIG1hdHJpeChOQSwgbnJvdyA9IG5fZm9sZHMsIG5jb2wgPSAxKQoKZm9yIChrIGluIDE6bl9mb2xkcykgewogIHRlc3RfaSA8LSB3aGljaChmb2xkc19pID09IGspCgogICMgUHJlcGFyZSB0aGUgZm9sZCBkYXRhc2V0cyAodHJhaW4gYW5kIHRlc3QpCiAgdHJhaW5mb2xkIDwtIFJlZHVjZWREYXRhU2V0Wy10ZXN0X2ksIF0KICB0ZXN0Zm9sZCA8LSBSZWR1Y2VkRGF0YVNldFt0ZXN0X2ksIF0KICAKICAjIE5vdyBmZWVkIGl0IHRvIHZnbG0KICBmaXR0ZWRfbW9kZWwgPC0gdmdsbShmb3JtdWxhID0gcHJpY2VfcmFuZ2UgfiAgLiAsIGRhdGE9dHJhaW5mb2xkLCBmYW1pbHk9bXVsdGlub21pYWwpCiAgCiAgcHJlZGljdGlvbnM9cHJlZGljdChmaXR0ZWRfbW9kZWwsIHRlc3Rmb2xkLCB0eXBlID0icmVzcG9uc2UiKQogIHByZWRpY3Rpb25zCiAgcHJlZGljdGlvbnMucmVzdWx0cyA8LSBpZmVsc2UocHJlZGljdGlvbnMgPiAwLjUsICJ5ZXMiLCAibm8iKSAjIHRyYW5zZm9ybSB0aGUgb3V0cHV0IGluICJ5ZXMvbm8iCiAgcHJlZGljdGlvbnMucmVzdWx0cwogIAogIHRydWVfcmVzdWx0X3ByaWNlX3JhbmdlIDwtIHByZWRpY3Rpb25zLnJlc3VsdHMgIyBjb3B5IHRvIGdldCB0aGUgCiAgdHJ1ZV9yZXN1bHRfcHJpY2VfcmFuZ2VbLDFdIDwtIGlmZWxzZSh0ZXN0Zm9sZFssM10gPT0gMCwgInllcyIsICJubyIpICMgdHJhbnNmb3JtIHRoZSBvdXRwdXQgaW4gInllcy9ubyIKICB0cnVlX3Jlc3VsdF9wcmljZV9yYW5nZVssMl0gPC0gaWZlbHNlKHRlc3Rmb2xkWywzXSA9PSAxLCAieWVzIiwgIm5vIikgIyB0cmFuc2Zvcm0gdGhlIG91dHB1dCBpbiAieWVzL25vIgogIHRydWVfcmVzdWx0X3ByaWNlX3JhbmdlWywzXSA8LSBpZmVsc2UodGVzdGZvbGRbLDNdID09IDIsICJ5ZXMiLCAibm8iKSAjIHRyYW5zZm9ybSB0aGUgb3V0cHV0IGluICJ5ZXMvbm8iCiAgdHJ1ZV9yZXN1bHRfcHJpY2VfcmFuZ2VbLDRdIDwtIGlmZWxzZSh0ZXN0Zm9sZFssM10gPT0gMywgInllcyIsICJubyIpICMgdHJhbnNmb3JtIHRoZSBvdXRwdXQgaW4gInllcy9ubyIKICAKICB0cnVlX3Jlc3VsdF9wcmljZV9yYW5nZQogIAogICMgQ29tcHV0ZSB0aGUgY29uZnVzaW9uIG1hdHJpeCBhbmQgdGhlIGFjY3VyYWN5CiAgY00gPC0gY29uZnVzaW9uTWF0cml4KGFzLmZhY3RvcihwcmVkaWN0aW9ucy5yZXN1bHRzKSwgYXMuZmFjdG9yKHRydWVfcmVzdWx0X3ByaWNlX3JhbmdlKSwgcG9zaXRpdmUgPSAieWVzIikKICBjTQogIGFjY3VyYWN5W2tdIDwtIGNNJG92ZXJhbGxbMV0KICBzZW5zaXRpdml0eVtrXSA8LSBjTSRieUNsYXNzWzFdICMgdHJ1ZSBwb3NpdGl2ZSByYXRlCiAgc3BlY2lmaWNpdHlba10gPC0gY00kYnlDbGFzc1syXSAjIHRydWUgbmVnYXRpdmUgcmF0ZQogIAogIHNjb3JlIDwtIEYxX1Njb3JlKHlfcHJlZCA9IHByZWRpY3Rpb25zLnJlc3VsdHMsIHlfdHJ1ZSA9IHRydWVfcmVzdWx0X3ByaWNlX3JhbmdlKQogIHByaW50KHBhc3RlMChrLCBwYXN0ZTAoIiBuYkZvbGQsIFNjb3JlIEYgOiAiLCBzY29yZSkpKQp9CgoKIyBQbG90IHRoZSBhY2N1cmFjeSwgdGhlIGZhbHNlIG5lZ2F0aXZlIHJhdGUgYW5kIHRoZSBmYWxzZSBwb3NpdGl2ZSByYXRlCnBhcihtZnJvdyA9IGMoMiwgMikpICMgcGxvdCB0aGUgcmVzdWx0cyBvbiB0aGUgc2FtZSBmaWd1cmUKCnBsdDEgPC0gcGxvdChzZXEoMSxuX2ZvbGRzKSwgYWNjdXJhY3ksIAogICAgIHR5cGUgPSAibCIsIGx3ZCA9IDIsIGNvbCA9ICJibHVlIiwgCiAgICAgeWxhYiA9ICJBY2N1cmFjeSIsIHhsYWIgPSAiRm9sZCBudW1iZXIiLCAKICAgICBtYWluID0gcGFzdGUwKG5fZm9sZHMsICItZm9sZCBDcm9zcy1WYWxpZGF0aW9uIiksIAogICAgIHlsaW0gPSBjKDAuMDEsIDEpIAogICAgICkKCnBsdDI8LXBsb3Qoc2VxKDEsbl9mb2xkcyksIDEtc2Vuc2l0aXZpdHksIAogICAgIHR5cGUgPSAibCIsIGx3ZCA9IDIsIGNvbCA9ICJyZWQiLCAKICAgICB5bGFiID0gIkZhbHNlIG5lZ2F0aXZlIHJhdGUiLCB4bGFiID0gIkZvbGQgbnVtYmVyIiwgCiAgICAgbWFpbiA9IHBhc3RlMChuX2ZvbGRzLCAiLWZvbGQgQ3Jvc3MtVmFsaWRhdGlvbiIpLCAKICAgICB5bGltID0gYygwLjAxLCAxKSAKKQoKcGx0MzwtcGxvdChzZXEoMSxuX2ZvbGRzKSwgMS1zcGVjaWZpY2l0eSwgCiAgICAgdHlwZSA9ICJsIiwgbHdkID0gMiwgY29sID0gImdyZWVuIiwgCiAgICAgeWxhYiA9ICJGYWxzZSBwb3NpdGl2ZSByYXRlIiwgeGxhYiA9ICJGb2xkIG51bWJlciIsIAogICAgIG1haW4gPSBwYXN0ZTAobl9mb2xkcywgIi1mb2xkIENyb3NzLVZhbGlkYXRpb24iKSwgCiAgICAgeWxpbSA9IGMoMC4wMSwgMSkgCikKCmBgYAoKa05OIGNsYXNzaWZpZXIgb24gYmF0dGVyeSBhbmQgcmFtIGZvciBwcmljZSByYW5nZQpgYGB7cn0KbGlicmFyeShWR0FNKQpsaWJyYXJ5KGNsYXNzKQpzZWVkIDwtIDE4MDkKc2V0LnNlZWQoc2VlZCkKCmxpYnJhcnkoY2FyZXQpICMgRm9yIHRoZSBjb25mdXNpb24gbWF0cml4CmxpYnJhcnkoTUxtZXRyaWNzKQoKbiA8LSBucm93KGRhdGFTZXQpCiMgU2VsZWN0IG9ubHkgdGhlIHJlbGV2YW50IHZhcmlhYmxlcwpSZWR1Y2VkRGF0YVNldCA8LSBzdWJzZXQoZGF0YVNldCwgc2VsZWN0PWMoImJhdHRlcnlfcG93ZXIiLCAicmFtIiwgInByaWNlX3JhbmdlIikpCgojIERlZmluZSB0aGUgZm9sZHMKbl9mb2xkcyA8LSAxMCAjIG51bWJlciBvZiBmb2xkcwpmb2xkc19pIDwtIHNhbXBsZShyZXAoMTpuX2ZvbGRzLCBsZW5ndGgub3V0ID0gbikpICMgZ2VuZXJhdGUgdGhlIGZvbGRzCgojIEluaXRpYWxpemF0aW9uIG9mIHRoZSBvdXRwdXRzCmFjY3VyYWN5IDwtIG1hdHJpeChOQSwgbnJvdyA9IG5fZm9sZHMsIG5jb2wgPSAxKQpzZW5zaXRpdml0eSA8LSBtYXRyaXgoTkEsIG5yb3cgPSBuX2ZvbGRzLCBuY29sID0gMSkKc3BlY2lmaWNpdHkgPC0gbWF0cml4KE5BLCBucm93ID0gbl9mb2xkcywgbmNvbCA9IDEpCgpmb3IgKGsgaW4gMTpuX2ZvbGRzKSB7CiAgdGVzdF9pIDwtIHdoaWNoKGZvbGRzX2kgPT0gaykKCiAgIyBQcmVwYXJlIHRoZSBmb2xkIGRhdGFzZXRzICh0cmFpbiBhbmQgdGVzdCkKICB0cmFpbmZvbGQgPC0gUmVkdWNlZERhdGFTZXRbLXRlc3RfaSwgXQogIHRlc3Rmb2xkIDwtIFJlZHVjZWREYXRhU2V0W3Rlc3RfaSwgXQogIAogICMgTm93IGZlZWQgaXQgdG8gdmdsbQogICNmaXR0ZWRfbW9kZWwgPC0gdmdsbShmb3JtdWxhID0gcHJpY2VfcmFuZ2UgfiAgLiAsIGRhdGE9dHJhaW5mb2xkLCBmYW1pbHk9bXVsdGlub21pYWwpCiAgCiAgZml0dGVkX21vZGVsIDwtIGtubih0cmFpbmZvbGRbLDE6Ml0sIHRlc3Rmb2xkWywxOjJdLCB0cmFpbmZvbGQkcHJpY2VfcmFuZ2UsIGs9MykKICBjb25mdXNpb24gPC0gdGFibGUoZml0dGVkX21vZGVsLCB0ZXN0Zm9sZCRwcmljZV9yYW5nZSkKICBjb25mdXNpb24KICAKICBzY29yZSA8LSBGMV9TY29yZSh5X3ByZWQgPSBmaXR0ZWRfbW9kZWwsIHlfdHJ1ZSA9IHRlc3Rmb2xkJHByaWNlX3JhbmdlKQogIHByaW50KHBhc3RlMChrLCBwYXN0ZTAoIiBuYkZvbGQsIFNjb3JlIEYgOiAiLCBzY29yZSkpKQp9CgojIENyZWF0ZSBhIGRhdGFmcmFtZSB0byBzaW1wbGlmeSBjaGFydGluZwpwbG90LmRmID0gZGF0YS5mcmFtZSh0ZXN0Zm9sZCwgcHJlZGljdGVkID0gZml0dGVkX21vZGVsKQoKIyBVc2UgZ2dwbG90CiMgMi1EIHBsb3RzIGV4YW1wbGUgb25seQojIFNlcGFsLkxlbmd0aCB2cyBTZXBhbC5XaWR0aAoKIyBGaXJzdCB1c2UgQ29udmV4IGh1bGwgdG8gZGV0ZXJtaW5lIGJvdW5kYXJ5IHBvaW50cyBvZiBlYWNoIGNsdXN0ZXIKcGxvdC5kZjEgPSBkYXRhLmZyYW1lKHggPSBwbG90LmRmJGJhdHRlcnlfcG93ZXIsIAogICAgICAgICAgICAgICAgICAgICAgeSA9IHBsb3QuZGYkcmFtLCAKICAgICAgICAgICAgICAgICAgICAgIHRydWUgPSBwbG90LmRmJHByaWNlX3JhbmdlLAogICAgICAgICAgICAgICAgICAgICAgcHJlZGljdGVkID0gcGxvdC5kZiRwcmljZV9yYW5nZSkKCmZpbmRfaHVsbCA9IGZ1bmN0aW9uKGRmKSBkZltjaHVsbChkZiR4LCBkZiR5KSwgXQpib3VuZGFyeSA9IGRkcGx5KHBsb3QuZGYxLCAudmFyaWFibGVzID0gInByZWRpY3RlZCIsIC5mdW4gPSBmaW5kX2h1bGwpCgoKZ2dwbG90KHBsb3QuZGYsIGFlcyhiYXR0ZXJ5X3Bvd2VyLCByYW0sIGNvbG9yID0gcHJlZGljdGVkLCBmaWxsID0gcHJlZGljdGVkKSkgKyAKICBnZW9tX3BvaW50KHNpemUgPSA1KSArIAogIGdlb21fcG9seWdvbihkYXRhID0gYm91bmRhcnksIGFlcyh4LHkpLCBhbHBoYSA9IDAuNSkKYGBgCgpTVk0gY2xhc3NpZmllciBvbiBiYXR0ZXJ5IGFuZCByYW0gZm9yIHByaWNlIHJhbmdlCmBgYHtyfQpsaWJyYXJ5KGUxMDcxKQoKZXh0cmFjdERhdGFGcm9tRGF0YVNldCA8LSAgZGF0YVNldCAlPiUgc2VsZWN0KDEsIDE0LCAyMSkKCiMgZMOpY2xhcmF0aW9uIGRlcyBkb25uw6llcwojIGxlIG1vZMOobGUgZXN0IGNhbGN1bMOpIGF2ZWMgbGVzIHZhbGV1cnMKIyBwYXIgZMOpZmF1dCBkZXMgcGFyYW3DqHRyZXMKIyAobm95YXUgZ2F1c3NpZW4sIHDDqW5hbGlzYXRpb24gw6AgMSwgZ2FtbWE9MCwyNSkKbW9kZWwgPSBzdm0ocHJpY2VfcmFuZ2UgfiAuLCBkYXRhID0gZXh0cmFjdERhdGFGcm9tRGF0YVNldCkKcHJpbnQobW9kZWwpCnN1bW1hcnkobW9kZWwpCgojIHByw6l2aXNpb24gZGUgbCfDqWNoYW50aWxsb24gZCdhcHByZW50aXNzYWdlCnByZWQgPSBwcmVkaWN0KG1vZGVsLCBleHRyYWN0RGF0YUZyb21EYXRhU2V0WywxOjJdKQoKIyBNYXRyaWNlIGRlIGNvbmZ1c2lvbiBwb3VyIGwnw6ljaGFudGlsbG9uCiMgZCdhcHByZW50aXNzYWdlCgp0YWJsZShwcmVkLCBleHRyYWN0RGF0YUZyb21EYXRhU2V0JHByaWNlX3JhbmdlKQojIFZpc3VhbGlzYXRpb24gZGVzIGNsYXNzZXMgKGNvdWxldXJzKQojIGV0IGRlcyB2ZWN0ZXVycyBzdXBwb3J0cyAoIisiKQoKc2NvcmUgPC0gRjFfU2NvcmUoeV9wcmVkID0gcHJlZCwgeV90cnVlID0gZXh0cmFjdERhdGFGcm9tRGF0YVNldCRwcmljZV9yYW5nZSkKcHJpbnQocGFzdGUwKCIgbmJGb2xkLCBTY29yZSBGIDogIiwgc2NvcmUpKQoKcGxvdChjbWRzY2FsZShkaXN0KGV4dHJhY3REYXRhRnJvbURhdGFTZXRbLC0zXSkpLApjb2wgPSBhcy5pbnRlZ2VyKGV4dHJhY3REYXRhRnJvbURhdGFTZXRbLDNdKSwKcGNoID0gYygibyIsIisiLCAiLSIsICJ4IilbMToxNTAgJWluJSBtb2RlbCRpbmRleCArIDFdKQpgYGAKCkdsb2JhbCBuYWl2ZUJheWVzIHRlc3Qgb24gcXVhbGlmZXIKYGBge3J9CmxpYnJhcnkoZTEwNzEpCmxpYnJhcnkoTUxtZXRyaWNzKQpwZXJjZW50YWdlX29mX2RhdGFfZm9yX3RyYWluaW5nIDwtIDAuOTAKZXh0cmFjdERhdGFGcm9tRGF0YVNldCA8LSAgZGF0YVNldCAlPiVzZWxlY3QoMSw3LDE0LDIxKQpuYkNvbHVtbkZvclRyYWluaW5nIDwtIG5yb3coZXh0cmFjdERhdGFGcm9tRGF0YVNldCkqcGVyY2VudGFnZV9vZl9kYXRhX2Zvcl90cmFpbmluZwpuYlJvd0ZvclRyYWluaW5nIDwtIG5jb2woZXh0cmFjdERhdGFGcm9tRGF0YVNldCkKbSA8LSBuYWl2ZUJheWVzKAogIGV4dHJhY3REYXRhRnJvbURhdGFTZXRbMDpuYkNvbHVtbkZvclRyYWluaW5nLC1uYlJvd0ZvclRyYWluaW5nXSwKICBleHRyYWN0RGF0YUZyb21EYXRhU2V0WzA6bmJDb2x1bW5Gb3JUcmFpbmluZyxuYlJvd0ZvclRyYWluaW5nXSwKICBlcHMgPSAxKQpwcmVkX3Jlc3VsdCA8LSBwcmVkaWN0KG0sIGV4dHJhY3REYXRhRnJvbURhdGFTZXRbbmJDb2x1bW5Gb3JUcmFpbmluZzpucm93KGV4dHJhY3REYXRhRnJvbURhdGFTZXQpLF0pCnRydWVfcmVzdWx0IDwtIGV4dHJhY3REYXRhRnJvbURhdGFTZXRbbmJDb2x1bW5Gb3JUcmFpbmluZzpucm93KGV4dHJhY3REYXRhRnJvbURhdGFTZXQpLG5jb2woZXh0cmFjdERhdGFGcm9tRGF0YVNldCldCnNjb3JlIDwtIEYxX1Njb3JlKHlfcHJlZCA9IHByZWRfcmVzdWx0LCB5X3RydWUgPSB0cnVlX3Jlc3VsdCkKcHJpbnQoc2NvcmUpCmBgYA==